#include "bsp_wifi.h"
#include <stdio.h>
#include <string.h>

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/event_groups.h>

#include <esp_log.h>
#include <esp_wifi.h>
#include <esp_event.h>
#include <nvs_flash.h>

#include <wifi_provisioning/manager.h>
#include <wifi_provisioning/scheme_ble.h>

#include "qrcode.h"

static const char *TAG = "app";

const int WIFI_CONNECTED_EVENT = BIT0;
static EventGroupHandle_t wifi_event_group;

#define PROV_QR_VERSION "v1"
#define PROV_TRANSPORT_BLE "ble"
#define QRCODE_BASE_URL "https://espressif.github.io/esp-jumpstart/qrcode.html"
// 移除PoP密钥，非安全模式不需要

static uint8_t cnt = 0;

static void event_handler(void *arg, esp_event_base_t event_base,
                          int32_t event_id, void *event_data)
{
    if (event_base == WIFI_PROV_EVENT)
    {
        switch (event_id)
        {
        case WIFI_PROV_START:
            ESP_LOGI(TAG, "Provisioning started");
            break;
        case WIFI_PROV_CRED_RECV:
        {
            wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data;
            ESP_LOGI(TAG, "Received Wi-Fi credentials"
                          "\n\tSSID     : %s\n\tPassword : %s",
                     (const char *)wifi_sta_cfg->ssid,
                     (const char *)wifi_sta_cfg->password);
            break;
        }
        case WIFI_PROV_CRED_FAIL:
        {
            wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data;
            ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s"
                          "\n\tPlease reset to factory and retry provisioning",
                     (*reason == WIFI_PROV_STA_AUTH_ERROR) ? "Wi-Fi station authentication failed" : "Wi-Fi access-point not found");
            break;
        }
        case WIFI_PROV_CRED_SUCCESS:
            ESP_LOGI(TAG, "Provisioning successful");
            break;
        case WIFI_PROV_END:
            wifi_prov_mgr_deinit();
            break;
        default:
            break;
        }
    }
    else if (event_base == WIFI_EVENT)
    {
        switch (event_id)
        {
        case WIFI_EVENT_STA_START:
            esp_wifi_connect();
            break;
        case WIFI_EVENT_STA_DISCONNECTED:
            ESP_LOGI(TAG, "Disconnected. Connecting to the AP again...");

            cnt++;
            if (cnt > 5)
            {
                wifi_prov_mgr_reset_provisioning();
                esp_restart();
            }

            esp_wifi_connect();
            break;

        default:
            break;
        }
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
    {
        display_del_qr();

        cnt = 0; // 重置计数器
        ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
        ESP_LOGI(TAG, "Connected with IP Address:" IPSTR, IP2STR(&event->ip_info.ip));
        xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_EVENT);
    }
    else if (event_base == PROTOCOMM_TRANSPORT_BLE_EVENT)
    {
        switch (event_id)
        {
        case PROTOCOMM_TRANSPORT_BLE_CONNECTED:
            ESP_LOGI(TAG, "BLE transport: Connected!");
            break;
        case PROTOCOMM_TRANSPORT_BLE_DISCONNECTED:
            ESP_LOGI(TAG, "BLE transport: Disconnected!");
            break;
        default:
            break;
        }
    }
    // 移除安全会话相关事件处理，非安全模式不需要
}

static void wifi_init_sta(void)
{
    /* Start Wi-Fi in station mode */
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_start());
}

static void get_device_service_name(char *service_name, size_t max)
{
    uint8_t eth_mac[6];
    const char *ssid_prefix = "PROV_";
    esp_wifi_get_mac(WIFI_IF_STA, eth_mac);
    snprintf(service_name, max, "%s%02X%02X%02X",
             ssid_prefix, eth_mac[3], eth_mac[4], eth_mac[5]);
}

static void wifi_prov_print_qr(const char *name, const char *username, const char *transport)
{
    if (!name || !transport)
    {
        ESP_LOGW(TAG, "Cannot generate QR code payload. Data missing.");
        return;
    }

    char payload[150] = {0};

    // 非安全模式QR码不包含pop字段
    snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\""
                                       ",\"transport\":\"%s\"}",
             PROV_QR_VERSION, name, transport);

    ESP_LOGI(TAG, "Scan this QR code from the provisioning application for Provisioning.");
    esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT();
    esp_qrcode_generate(&cfg, payload);
    display_show_qr(payload);
    ESP_LOGI(TAG, "If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s", QRCODE_BASE_URL, payload);
}

void bsp_wifi_init(void)
{
    /* Initialize NVS partition */
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ESP_ERROR_CHECK(nvs_flash_init());
    }

    /* Initialize TCP/IP */
    ESP_ERROR_CHECK(esp_netif_init());

    /* Initialize the event loop */
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    wifi_event_group = xEventGroupCreate();

    /* Register our event handler for Wi-Fi, IP and Provisioning related events */
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_PROV_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_TRANSPORT_BLE_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));

    // 移除安全会话事件注册，非安全模式不需要
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));

    /* Initialize Wi-Fi including netif with default config */
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    /* Configuration for the provisioning manager */
    wifi_prov_mgr_config_t config = {
        .scheme = wifi_prov_scheme_ble,
        .scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM};

    ESP_ERROR_CHECK(wifi_prov_mgr_init(config));

    bool provisioned = false;
    ESP_ERROR_CHECK(wifi_prov_mgr_is_provisioned(&provisioned));

    if (!provisioned)
    {
        ESP_LOGI(TAG, "Starting provisioning in non-secure mode");

        char service_name[12];
        get_device_service_name(service_name, sizeof(service_name));

        // 使用非安全模式
        wifi_prov_security_t security = WIFI_PROV_SECURITY_0;

        // 非安全模式不需要PoP和安全参数
        const void *sec_params = NULL;

        const char *username = NULL;
        const char *service_key = NULL;

        uint8_t custom_service_uuid[] = {
            0xb4,
            0xdf,
            0x5a,
            0x1c,
            0x3f,
            0x6b,
            0xf4,
            0xbf,
            0xea,
            0x4a,
            0x82,
            0x03,
            0x04,
            0x90,
            0x1a,
            0x02,
        };

        wifi_prov_scheme_ble_set_service_uuid(custom_service_uuid);

        /* Start provisioning service with non-secure parameters */
        ESP_ERROR_CHECK(wifi_prov_mgr_start_provisioning(security, sec_params, service_name, service_key));

        // 非安全模式打印QR码（不含pop）
        wifi_prov_print_qr(service_name, username, PROV_TRANSPORT_BLE);
    }
    else
    {
        ESP_LOGI(TAG, "Already provisioned, starting Wi-Fi STA");

        wifi_prov_mgr_deinit();
        ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
        wifi_init_sta();
    }

    /* Wait for Wi-Fi connection */
    xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, true, true, portMAX_DELAY);
}

// #include <stdio.h>
// #include <string.h>

// #include <freertos/FreeRTOS.h>
// #include <freertos/task.h>
// #include <freertos/event_groups.h>

// #include <esp_log.h>
// #include <esp_wifi.h>
// #include <esp_event.h>
// #include <nvs_flash.h>

// #include <wifi_provisioning/manager.h>

// #include <wifi_provisioning/scheme_ble.h>

// #include "qrcode.h"

// static const char *TAG = "app";

// const int WIFI_CONNECTED_EVENT = BIT0;
// static EventGroupHandle_t wifi_event_group;

// #define PROV_QR_VERSION "v1"
// #define PROV_TRANSPORT_BLE "ble"
// #define QRCODE_BASE_URL "https://espressif.github.io/esp-jumpstart/qrcode.html"
// #define PROV_POP "123456" // 配网密钥

// static uint8_t cnt = 0;
// // static uint8_t retries = 0;

// static void event_handler(void *arg, esp_event_base_t event_base,
//                           int32_t event_id, void *event_data)
// {
//     if (event_base == WIFI_PROV_EVENT)
//     {
//         switch (event_id)
//         {
//         case WIFI_PROV_START:
//             ESP_LOGI(TAG, "Provisioning started");
//             break;
//         case WIFI_PROV_CRED_RECV:
//         {
//             wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data;
//             ESP_LOGI(TAG, "Received Wi-Fi credentials"
//                           "\n\tSSID     : %s\n\tPassword : %s",
//                      (const char *)wifi_sta_cfg->ssid,
//                      (const char *)wifi_sta_cfg->password);
//             break;
//         }
//         case WIFI_PROV_CRED_FAIL:
//         {
//             wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data;
//             ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s"
//                           "\n\tPlease reset to factory and retry provisioning",
//                      (*reason == WIFI_PROV_STA_AUTH_ERROR) ? "Wi-Fi station authentication failed" : "Wi-Fi access-point not found");

//             break;
//         }
//         case WIFI_PROV_CRED_SUCCESS:
//             ESP_LOGI(TAG, "Provisioning successful");
//             break;
//         case WIFI_PROV_END:
//             wifi_prov_mgr_deinit();
//             break;
//         default:
//             break;
//         }
//     }
//     else if (event_base == WIFI_EVENT)
//     {
//         switch (event_id)
//         {
//         case WIFI_EVENT_STA_START:
//             esp_wifi_connect();
//             break;
//         case WIFI_EVENT_STA_DISCONNECTED:
//             ESP_LOGI(TAG, "Disconnected. Connecting to the AP again...");

//             cnt++;
//             if (cnt > 5)
//             {
//                 wifi_prov_mgr_reset_provisioning();
//                 esp_restart();
//             }

//             esp_wifi_connect();
//             break;

//         default:
//             break;
//         }
//     }
//     else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
//     {
//         cnt = 0; // 重置计数器
//         ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
//         ESP_LOGI(TAG, "Connected with IP Address:" IPSTR, IP2STR(&event->ip_info.ip));
//         /* Signal main application to continue execution */
//         xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_EVENT);
//         // #ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
//     }
//     else if (event_base == PROTOCOMM_TRANSPORT_BLE_EVENT)
//     {
//         switch (event_id)
//         {
//         case PROTOCOMM_TRANSPORT_BLE_CONNECTED:
//             ESP_LOGI(TAG, "BLE transport: Connected!");
//             break;
//         case PROTOCOMM_TRANSPORT_BLE_DISCONNECTED:
//             ESP_LOGI(TAG, "BLE transport: Disconnected!");
//             break;
//         default:
//             break;
//         }
//         // #endif
//     }
//     else if (event_base == PROTOCOMM_SECURITY_SESSION_EVENT)
//     {
//         switch (event_id)
//         {
//         case PROTOCOMM_SECURITY_SESSION_SETUP_OK:
//             ESP_LOGI(TAG, "Secured session established!");
//             break;
//         case PROTOCOMM_SECURITY_SESSION_INVALID_SECURITY_PARAMS:
//             ESP_LOGE(TAG, "Received invalid security parameters for establishing secure session!");
//             break;
//         case PROTOCOMM_SECURITY_SESSION_CREDENTIALS_MISMATCH:
//             ESP_LOGE(TAG, "Received incorrect username and/or PoP for establishing secure session!");
//             break;
//         default:
//             break;
//         }
//     }
// }

// static void wifi_init_sta(void)
// {
//     /* Start Wi-Fi in station mode */
//     ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
//     ESP_ERROR_CHECK(esp_wifi_start());
// }

// static void get_device_service_name(char *service_name, size_t max)
// {
//     uint8_t eth_mac[6];
//     const char *ssid_prefix = "PROV_";
//     esp_wifi_get_mac(WIFI_IF_STA, eth_mac);
//     snprintf(service_name, max, "%s%02X%02X%02X",
//              ssid_prefix, eth_mac[3], eth_mac[4], eth_mac[5]);
// }

// static void wifi_prov_print_qr(const char *name, const char *username, const char *pop, const char *transport)
// {
//     if (!name || !transport)
//     {
//         ESP_LOGW(TAG, "Cannot generate QR code payload. Data missing.");
//         return;
//     }

//     char payload[150] = {0};

//     snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\""
//                                        ",\"pop\":\"%s\",\"transport\":\"%s\"}",
//              PROV_QR_VERSION, name, pop, transport);

//     ESP_LOGI(TAG, "Scan this QR code from the provisioning application for Provisioning.");
//     esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT();
//     esp_qrcode_generate(&cfg, payload);
//     ESP_LOGI(TAG, "If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s", QRCODE_BASE_URL, payload);
// }

// void bsp_wifi_init(void)
// {
//     /* Initialize NVS partition */
//     esp_err_t ret = nvs_flash_init();
//     if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
//     {
//         /* NVS partition was truncated
//          * and needs to be erased */
//         ESP_ERROR_CHECK(nvs_flash_erase());

//         /* Retry nvs_flash_init */
//         ESP_ERROR_CHECK(nvs_flash_init());
//     }

//     /* Initialize TCP/IP */
//     ESP_ERROR_CHECK(esp_netif_init());

//     /* Initialize the event loop */
//     ESP_ERROR_CHECK(esp_event_loop_create_default());
//     wifi_event_group = xEventGroupCreate();

//     /* Register our event handler for Wi-Fi, IP and Provisioning related events */
//     ESP_ERROR_CHECK(esp_event_handler_register(WIFI_PROV_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
//     ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_TRANSPORT_BLE_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));

//     ESP_ERROR_CHECK(esp_event_handler_register(PROTOCOMM_SECURITY_SESSION_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
//     ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));

//     /* Initialize Wi-Fi including netif with default config */
//     esp_netif_create_default_wifi_sta();

//     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
//     ESP_ERROR_CHECK(esp_wifi_init(&cfg));

//     /* Configuration for the provisioning manager */
//     wifi_prov_mgr_config_t config = {
//         .scheme = wifi_prov_scheme_ble,
//         .scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM};

//     ESP_ERROR_CHECK(wifi_prov_mgr_init(config));

//     bool provisioned = false;

//     ESP_ERROR_CHECK(wifi_prov_mgr_is_provisioned(&provisioned));

//     if (!provisioned)
//     {
//         ESP_LOGI(TAG, "Starting provisioning");

//         char service_name[12];
//         get_device_service_name(service_name, sizeof(service_name));

//         wifi_prov_security_t security = WIFI_PROV_SECURITY_1;

//         const char *pop = PROV_POP;

//         wifi_prov_security1_params_t *sec_params = pop;

//         const char *username = NULL;

//         const char *service_key = NULL;

//         uint8_t custom_service_uuid[] = {
//             /* LSB <---------------------------------------
//              * ---------------------------------------> MSB */
//             0xb4,
//             0xdf,
//             0x5a,
//             0x1c,
//             0x3f,
//             0x6b,
//             0xf4,
//             0xbf,
//             0xea,
//             0x4a,
//             0x82,
//             0x03,
//             0x04,
//             0x90,
//             0x1a,
//             0x02,
//         };

//         wifi_prov_scheme_ble_set_service_uuid(custom_service_uuid);

//         // wifi_prov_mgr_endpoint_create("custom-data");

//         /* Start provisioning service */
//         ESP_ERROR_CHECK(wifi_prov_mgr_start_provisioning(security, (const void *)sec_params, service_name, service_key));

//         // wifi_prov_mgr_endpoint_register("custom-data", custom_prov_data_handler, NULL);

//         wifi_prov_print_qr(service_name, username, pop, PROV_TRANSPORT_BLE);
//     }
//     else
//     {
//         ESP_LOGI(TAG, "Already provisioned, starting Wi-Fi STA");

//         wifi_prov_mgr_deinit();

//         ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));

//         wifi_init_sta();
//     }

//     /* Wait for Wi-Fi connection */
//     xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, true, true, portMAX_DELAY);
// }